package hermesV3.services.TupleSpace;

import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Represents a generic tuple.
 * 
 * @author Luigi Ambruoso, Vincenzo Addeo, Federico Buti
 */
public class Tuple implements Serializable {

	private static final long serialVersionUID = -6934617783388904686L;
	private Set<String> keys;
	private Map<String, Object> fields;

	/**
	 * @param keys
	 * @param fieldName
	 */
	public Tuple(Set<String> keys, Set<String> fieldName) {
		this.keys = new HashSet<String>();
		// inserisco le chiavi con caratteri piccoli
		for (String s : keys) {
			keys.add(s.toLowerCase());
		}

		fields = new HashMap<String, Object>();
		for (String s : fieldName) {
			fields.put(s.toLowerCase(), null);
		}
	}

	/**
	 * Builds a tuple.
	 */
	public Tuple() {
		this.keys = new HashSet<String>();
		fields = new HashMap<String, Object>();

	}

	/**
	 * Adds the specific key to the tuple.
	 * 
	 * @param key
	 *            The key to be added.
	 */
	public void addKey(String key) {
		String k = key.toLowerCase();
		keys.add(k);

	}

	/**
	 * @param name
	 * @param field
	 * @throws TupleException
	 */
	public void addField(String name, Object field) throws TupleException {
		String n = name.toLowerCase();
		if (!fields.containsKey(n))
			fields.put(n, field);
		else
			throw new TupleException("None Campo già esistente");

	}

	/**
	 * @return The keys.
	 */
	public Set<String> getKeys() {
		return keys;
	}

	/**
	 * @param name
	 * @param field
	 * @throws TupleException
	 */
	public void setField(String name, Object field) throws TupleException {
		if (fields.containsKey(name.toLowerCase()))
			fields.put(name.toLowerCase(), field);
		else
			throw new TupleException("None Campo Errato");
	}

	/**
	 * @param name
	 * @return The field
	 * @throws TupleException
	 */
	public Object getField(String name) throws TupleException {
		if (fields.containsKey(name.toLowerCase()))
			return fields.get(name.toLowerCase());
		throw new TupleException("None Campo Inesistente");
	}

	/**
	 * This method compares the tuple of the space with obj
	 * 
	 * @param obj
	 * @return true if this has the feature of obj, else false
	 */
	public boolean equalsSearch(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Tuple))
			return false;
		Tuple other = (Tuple) obj;
		// probabilmente non serve
		if (!other.keys.isEmpty()) {
			// se other.keys non contiene tutte le chiavi di this.keys ritorno
			// false;

			for (String s : other.keys) {
				if (!this.keys.contains(s))
					return false;
			}

		}
		if (!other.fields.isEmpty()) {
			/*
			 * se gli oggetti di other.fields non ci sono o non sono uguali a
			 * quelli di this.fields allora ritorno false
			 */
			for (String k : other.fields.keySet()) {
				if (this.fields.containsKey(k)) {
					if (this.fields.get(k) != other.fields.get(k)) {
						if (this.fields.get(k) != null)
							return false;
						if (!this.fields.get(k).equals(other.fields.get(k)))
							return false;
					}

				} else
					return false;
			}
		}

		return true;

	}

	@Override
	public String toString() {
		String str = "--";
		for (String s : this.keys) {
			str += s + "--";
		}
		str += "\n";
		for (String s : this.fields.keySet()) {
			str += s + "::";
			if (this.fields.get(s) != null)
				str += this.fields.get(s).toString() + "\n";
			else
				str += "null\n";

		}
		return str;
	}
}
